

`include "defines.v"
/* verilator lint_off LATCH */
//----------------------------------------------------------------
//Module Name : cpu_ctrl.v
//Description of module:
//control signal genaration 
//----------------------------------------------------------------
//Designer:	Tang Pengyu
//Date: 2021/07/22	  
//----------------------------------------------------------------

module	cpu_ctrl(
		input	[7:0]	inst_opcode,
		input	branch_eq,
		input	branch_ne,
		input	branch_lt,
		input	branch_ge,
		input	branch_ltu,
		input	branch_geu,
		input	[63:0] ram_addr,
		input	time_intr_r,			//中断响应
		input	[63:0] load_store_addr,			//exe_data
		
		input	[6:0]	funct7,
		
		input	if_fetched,
		
		output	load_mem_en,
		
		output	load_axi_en,
		output	reg load_clint_en,
		output	store_axi_en,
		output	reg store_clint_en,
		
		output	jalr_en,
		output	jal_en,
		output	[1:0] wb_sel,
		output	pc_sel,
		output	store_mem_en,
		output	branch_en,
		
		output	reg [63:0] store_mask,
		
		output	ecall_en,
		output	mret_en
//		output	pc_from_mepc
		);
wire	jal_jalr_en;

//inst_lb,inst_lbu	,inst_lh,inst_lhu,inst_lw,inst_lwu,inst_ld
assign load_mem_en = (inst_opcode == 8'b000_00000) | (inst_opcode == 8'b100_00000)
					| (inst_opcode == 8'b001_00000) | (inst_opcode == 8'b101_00000)
					| (inst_opcode == 8'b010_00000) | (inst_opcode == 8'b110_00000)
					| (inst_opcode == 8'b011_00000);
//assign	load_clint_en = load_mem_en & 
//					((load_store_addr == 64'h0000_0000_0200_bff8) | (load_store_addr == 64'h0000_0000_0200_4000));					
assign	load_axi_en = load_mem_en & (~load_clint_en);

//assign pc_sel = (inst_opcode == 8'b000_11001);		//inst_jalr
assign jalr_en = (inst_opcode == 8'b000_11001);
assign jal_en = (inst_opcode[4:0] == 5'b11011);
assign jal_jalr_en = jal_en | jalr_en;
assign wb_sel = {load_mem_en,jal_jalr_en};

assign store_mem_en = (inst_opcode == 8'b000_01000) | (inst_opcode == 8'b001_01000)
					| (inst_opcode == 8'b010_01000) | (inst_opcode == 8'b011_01000);			//sb,sh,sw,sd
//assign	store_clint_en = store_mem_en &
//				((load_store_addr == 64'h0000_0000_0200_bff8) | (load_store_addr == 64'h0000_0000_0200_4000));
assign	store_axi_en = store_mem_en & (~store_clint_en);
					
					//beq bne blt bge bltu bgeu
assign	branch_en = (inst_opcode == 8'b000_11000) | (inst_opcode == 8'b001_11000)
					| (inst_opcode == 8'b100_11000) | (inst_opcode == 8'b101_11000)
					| (inst_opcode == 8'b110_11000) | (inst_opcode == 8'b111_11000);
//ecall_en
assign	ecall_en = ((inst_opcode == 8'b000_11100) & (funct7 == 7'b0000000)) ? 1'b1 : 1'b0;
					
//mret_en
assign	mret_en = ((inst_opcode == 8'b000_11100) & (funct7 == 7'b0011000)) ? 1'b1 : 1'b0;

//load_clint_en,store_clint_en
wire	clint_lock;
assign	clint_lock = if_fetched;
always @(*)	begin
	if(clint_lock == 1'b1)	begin
		load_clint_en = load_mem_en & 
			((load_store_addr == 64'h0000_0000_0200_bff8) | (load_store_addr == 64'h0000_0000_0200_4000));
		store_clint_en = store_mem_en &
			((load_store_addr == 64'h0000_0000_0200_bff8) | (load_store_addr == 64'h0000_0000_0200_4000));

	end
end



					
//pc_sel_t
reg		pc_sel_t;
always @(*)
  begin
	case(inst_opcode)
		8'b000_11001:	pc_sel_t = 1'b1;			//inst_jalr
		8'b000_11011,8'b001_11011,8'b010_11011,8'b011_11011,8'b100_11011,8'b101_11011,8'b110_11011,8'b111_11011:	
						pc_sel_t = 1'b1;			//inst_jal
		8'b000_11000:	pc_sel_t = branch_eq ? 1'b1 : 1'b0;			//beq
		8'b001_11000:	pc_sel_t = branch_ne ? 1'b1 : 1'b0;			//bne
		8'b100_11000:	pc_sel_t = branch_lt ? 1'b1 : 1'b0;			//blt
		8'b101_11000:	pc_sel_t = branch_ge ? 1'b1 : 1'b0;			//bge
		8'b110_11000:	pc_sel_t = branch_ltu ? 1'b1 : 1'b0;			//bltu
		8'b111_11000:	pc_sel_t = branch_geu ? 1'b1 : 1'b0;			//bgeu
		
		8'b000_11100:	pc_sel_t = 1'b1;					//ecall
		default:		pc_sel_t = 1'b0;
  
	endcase
  end
  
assign	pc_sel = time_intr_r ? 1'b1 : pc_sel_t;		//产生中断时一定跳转

always @(*)
  begin
	case(inst_opcode)
		8'b000_01000:	store_mask = (ram_addr[2:0] == 3'b000) ? 64'h0000_0000_0000_00ff :
									(ram_addr[2:0] == 3'b001) ? 64'h0000_0000_0000_ff00 :
									(ram_addr[2:0] == 3'b010) ? 64'h0000_0000_00ff_0000 :
									(ram_addr[2:0] == 3'b011) ? 64'h0000_0000_ff00_0000 :
									(ram_addr[2:0] == 3'b100) ? 64'h0000_00ff_0000_0000 :
									(ram_addr[2:0] == 3'b101) ? 64'h0000_ff00_0000_0000 :
									(ram_addr[2:0] == 3'b110) ? 64'h00ff_0000_0000_0000 :
									(ram_addr[2:0] == 3'b111) ? 64'hff00_0000_0000_0000 : 64'd0;			//sb
		8'b001_01000:	store_mask = (ram_addr[2:0] == 3'b000) ? 64'h0000_0000_0000_ffff :
									(ram_addr[2:0] == 3'b001) ? 64'h0000_0000_00ff_ff00 :
									(ram_addr[2:0] == 3'b010) ? 64'h0000_0000_ffff_0000 :
									(ram_addr[2:0] == 3'b011) ? 64'h0000_00ff_ff00_0000 :
									(ram_addr[2:0] == 3'b100) ? 64'h0000_ffff_0000_0000 :
									(ram_addr[2:0] == 3'b101) ? 64'h00ff_ff00_0000_0000 :
									(ram_addr[2:0] == 3'b110) ? 64'hffff_0000_0000_0000 : 64'd0;			//sh
		8'b010_01000:	store_mask = (ram_addr[2:0] == 3'b000) ? 64'h0000_0000_ffff_ffff :
									(ram_addr[2:0] == 3'b001) ? 64'h0000_00ff_ffff_ff00 :
									(ram_addr[2:0] == 3'b010) ? 64'h0000_ffff_ffff_0000 :
									(ram_addr[2:0] == 3'b011) ? 64'h00ff_ffff_ff00_0000 :
									(ram_addr[2:0] == 3'b100) ? 64'hffff_ffff_0000_0000 : 64'd0;			//sw
		8'b011_01000:	store_mask = 64'hffff_ffff_ffff_ffff;			//sd
		default:		store_mask = 64'h0000_0000_0000_0000;
	endcase
  end


endmodule